package cz.data.platform.web.listener;

import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import cz.data.common.core.DataConstant;
import cz.data.common.support.security.DiscoveryServiceHeaderFactory;
import cz.data.common.utils.SecurityUtil;
import cz.data.common.utils.ThrowableUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j
public class ApplicationReadyListener implements ApplicationListener<ApplicationReadyEvent> {

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        ConfigurableApplicationContext context = event.getApplicationContext();
        ConfigurableEnvironment environment = context.getEnvironment();
        NacosDiscoveryProperties discoveryProperties = context.getBean(NacosDiscoveryProperties.class);
        DiscoveryServiceHeaderFactory headerFactory = context.getBean(DiscoveryServiceHeaderFactory.class);
        String clientId = discoveryProperties.getMetadata().get("client-id");
        String serviceName = discoveryProperties.getService();
        String nacosServiceToken = SecurityUtil.createBasicToken(serviceName, clientId);
        log.info("当前服务密匙: {}, 服务内部鉴权Token: {}", clientId, nacosServiceToken);
        headerFactory.addHeader(DataConstant.Token.SERVICE_HEADER, nacosServiceToken);
        String banner = "\n-----------------------------------------\n" +
                "服务启动成功，时间：" + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()) + "\n" +
                "服务名称：" + environment.getProperty("spring.application.name") + "\n" +
                "注册地址：" + discoveryProperties.getIp() + ":" + environment.getProperty("server.port") + "\n" +
                "-----------------------------------------";
        log.info(banner);
        //todo fix nacos节点重新注册metadata下数据不覆盖问题
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);
        scheduledThreadPool.schedule(new NacosClientIdRunnable(context), 1, TimeUnit.MINUTES);
    }

    public static class NacosClientIdRunnable implements Runnable {
        private final ApplicationContext context;

        public NacosClientIdRunnable(ApplicationContext context) {
            this.context = context;
        }

        @Override
        public void run() {
            DiscoveryServiceHeaderFactory headerFactory = context.getBean(DiscoveryServiceHeaderFactory.class);
            NacosDiscoveryProperties discoveryProperties = context.getBean(NacosDiscoveryProperties.class);
            String serviceName = discoveryProperties.getService();
            String clientId = discoveryProperties.getMetadata().get("client-id");
            NacosServiceManager nacosServiceManager = context.getBean(NacosServiceManager.class);
            NamingService namingService = nacosServiceManager.getNamingService();
            //获取远程实例
            List<Instance> instances = ThrowableUtil.callable(() ->
                    namingService.getAllInstances(discoveryProperties.getService(),
                            discoveryProperties.getGroup(),
                            Collections.singletonList(discoveryProperties.getClusterName()))
            );
            if (CollectionUtils.isNotEmpty(instances)) {
                for (Instance instance : instances) {
                    if (StringUtils.equals(instance.getIp(), discoveryProperties.getIp())
                            && instance.getPort() == discoveryProperties.getPort()) {
                        String remoteClientId = instance.getMetadata().get("client-id");
                        if (!StringUtils.equals(remoteClientId, clientId)) {
                            log.warn("远程服务密匙[{}]和本地服务密匙[{}]不一致,刷新本地", remoteClientId, clientId);
                            String nacosServiceToken = SecurityUtil.createBasicToken(serviceName, remoteClientId);
                            log.info("当前服务密匙: {}, 服务内部鉴权Token: {}", remoteClientId, nacosServiceToken);
                            headerFactory.addHeader(DataConstant.Token.SERVICE_HEADER, nacosServiceToken);
                            discoveryProperties.getMetadata().put("client-id", remoteClientId);
                        }
                        break;
                    }
                }
            }
        }
    }
}
